package com.keba.lamp.complaint.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.keba.basic.annotation.log.WebLog;
import com.keba.basic.base.R;
import com.keba.basic.base.controller.SuperController;
import com.keba.basic.base.request.PageParams;
import com.keba.basic.context.ContextUtil;
import com.keba.basic.database.mybatis.conditions.Wraps;
import com.keba.basic.database.mybatis.conditions.query.QueryWrap;
import com.keba.basic.exception.BizException;
import com.keba.basic.interfaces.echo.EchoService;
import com.keba.basic.utils.BeanPlusUtil;
import com.keba.lamp.complaint.entity.AccountDetail;
import com.keba.lamp.complaint.entity.AccountPrepayment;
import com.keba.lamp.complaint.entity.Case;
import com.keba.lamp.complaint.enumeration.AccountTypeEnum;
import com.keba.lamp.complaint.enumeration.TransactionTypeEnum;
import com.keba.lamp.complaint.enumeration.TransferTypeEnum;
import com.keba.lamp.complaint.service.AccountDetailService;
import com.keba.lamp.complaint.service.AccountPrepaymentService;
import com.keba.lamp.complaint.service.CaseService;
import com.keba.lamp.complaint.vo.query.AccountDetailPageQuery;
import com.keba.lamp.complaint.vo.result.AccountDetailResultExcelVO;
import com.keba.lamp.complaint.vo.result.AccountDetailResultVO;
import com.keba.lamp.complaint.vo.result.AccountPrepaymentExportVO;
import com.keba.lamp.complaint.vo.save.AccountDetailSaveVO;
import com.keba.lamp.complaint.vo.update.AccountDetailUpdateVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * 账户明细
 * </p>
 *
 * @author twg
 * @date 2025-05-15 20:30:52
 * @create [2025-05-15 20:30:52] [twg] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Validated
@RestController
@RequestMapping("/accountDetail")
@Tag(name = "账户明细")
public class AccountDetailController extends SuperController<AccountDetailService, Long, AccountDetail
        , AccountDetailSaveVO, AccountDetailUpdateVO, AccountDetailPageQuery, AccountDetailResultVO> {
    private final EchoService echoService;

    @Override
    public EchoService getEchoService() {
        return echoService;
    }

    private final AccountPrepaymentService accountPrepaymentService;
    private final CaseService caseService;


    @Override
    public void handlerQueryParams(PageParams<AccountDetailPageQuery> params) {
        if (StrUtil.isNotEmpty(params.getModel().getTenantName())) {
            List<String> accountCodes = accountPrepaymentService.getSuperManager().list(Wraps.<AccountPrepayment>lbQ().like(AccountPrepayment::getName, params.getModel().getTenantName())).stream().map(AccountPrepayment::getCode).collect(Collectors.toList());
            params.getExtra().put("accountCode_in", new ArrayList<String>(CollUtil.isNotEmpty(accountCodes) ? accountCodes : Collections.singleton("null")));
        }
        super.handlerQueryParams(params);
    }

    @Override
    public void handlerResult(IPage<AccountDetailResultVO> page) {
        echoService.action(page.getRecords());
        page.getRecords().stream().forEach(o -> {
            AccountPrepayment accountPrepayment = accountPrepaymentService.getSuperManager().getOne(Wraps.<AccountPrepayment>lbQ().eq(AccountPrepayment::getCode, o.getAccountCode()));
            o.getEchoMap().putIfAbsent("type", TransferTypeEnum.getByCode(o.getType()).getDesc());
            o.getEchoMap().putIfAbsent("accountType", AccountTypeEnum.getByCode(o.getAccountType()).getDesc());
            o.getEchoMap().putIfAbsent("incomeExpenseType", TransactionTypeEnum.getByCode(o.getIncomeExpenseType()).getDesc());
            o.setAccountName(Objects.isNull(accountPrepayment) ? "" : accountPrepayment.getName());
            Long caseId = o.getCaseId();
            if (Objects.nonNull(caseId)) {
                Case caseEntity = caseService.getSuperManager().getById(caseId);
                Optional.ofNullable(caseEntity).ifPresent(c -> o.setBizDesc(c.getCaseName()));
            }
        });
    }


    @Operation(summary = "获取账户下的明细分页列表查询")
    @PostMapping(value = "/pageWithAccount")
    @WebLog(value = "'分页列表查询:第' + #params?.current + '页, 显示' + #params?.size + '行'", response = false)
    public R<IPage<AccountDetailResultVO>> pageWithAccount(@RequestBody PageParams<AccountDetailPageQuery> params) {
        IPage<AccountDetail> page = params.buildPage(getEntityClass());
        AccountPrepayment accountPrepayment = accountPrepaymentService.getByTenantId(ContextUtil.getTenantId());
        if (Objects.isNull(accountPrepayment)) {
            return R.success(BeanPlusUtil.toBeanPage(page, getResultVOClass()));
        }
        AccountDetail model = BeanUtil.toBean(params.getModel(), getEntityClass());
        if (Objects.isNull(model)) {
            model = new AccountDetail();
        }
        model.setAccountCode(accountPrepayment.getCode());
        // 根据前端传递的参数，构建查询条件【提供给子类重写】【有默认实现】
        QueryWrap<AccountDetail> wrapper = handlerWrapper(model, params);

        // 执行单表分页查询
        getSuperService().page(page, wrapper);
        IPage<AccountDetailResultVO> voPage = BeanPlusUtil.toBeanPage(page, getResultVOClass());
        handlerResult(voPage);
        return R.success(voPage);
    }


    @Operation(summary = "账单导出")
    @PostMapping("/export/bill")
    @WebLog(value = "账单导出")
    public void exportExcel(HttpServletResponse response,
                            @RequestBody @Validated PageParams<AccountDetailPageQuery> params) {
        try {
            params.setCurrent(1L);
            params.setSize(10000L);
            IPage<AccountDetail> page = params.buildPage(getEntityClass());
            AccountPrepayment accountPrepayment = accountPrepaymentService.getByTenantId(ContextUtil.getTenantId());
            List<AccountDetailResultExcelVO> excelVOList = new ArrayList<>();
            if (Objects.nonNull(accountPrepayment)) {
                AccountDetail model = BeanUtil.toBean(params.getModel(), getEntityClass());
                if (Objects.isNull(model)) {
                    model = new AccountDetail();
                }
                model.setAccountCode(accountPrepayment.getCode());
                // 根据前端传递的参数，构建查询条件【提供给子类重写】【有默认实现】
                QueryWrap<AccountDetail> wrapper = handlerWrapper(model, params);

                // 执行单表分页查询
                getSuperService().page(page, wrapper);
                IPage<AccountDetailResultVO> voPage = BeanPlusUtil.toBeanPage(page, getResultVOClass());
                handlerResult(voPage);

                if (CollectionUtils.isNotEmpty(voPage.getRecords())) {
                    excelVOList = voPage.getRecords().stream().map(vo -> {
                        Map<String, Object> echoMap = vo.getEchoMap();
                        AccountDetailResultExcelVO excelVO = new AccountDetailResultExcelVO();
                        Optional.ofNullable(echoMap.get("type")).ifPresent(type -> excelVO.setType(type.toString()));
                        Optional.ofNullable(echoMap.get("bizType")).ifPresent(bizType -> excelVO.setBizType(bizType.toString()));
                        excelVO.setBizTime(vo.getBizTime());
                        excelVO.setBizDesc(vo.getBizDesc());
                        excelVO.setCaseId(Objects.nonNull(vo.getCaseId()) ? String.valueOf(vo.getCaseId()) : null);
                        excelVO.setCode(vo.getCode());
                        Optional.ofNullable(echoMap.get("accountType")).ifPresent(accountType -> excelVO.setAccountType(accountType.toString()));
                        Optional.ofNullable(echoMap.get("incomeExpenseType")).ifPresent(incomeExpenseType -> excelVO.setIncomeExpenseType(incomeExpenseType.toString()));
                        excelVO.setAmount(vo.getAmount());
                        excelVO.setBalance(vo.getBalance());
                        excelVO.setBizTime1(vo.getBizTime());
                        excelVO.setBookingTime(vo.getBookingTime());
                        excelVO.setRemark(vo.getRemark());
                        return excelVO;
                    }).collect(Collectors.toList());
                }
            }

            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/x-download");
            String fileName = ("账单.xlsx");
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.reset();
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/octet-stream; charset=UTF-8");
            AccountPrepaymentExportVO accountPrepaymentExportVO = new AccountPrepaymentExportVO();
            Object startTime = params.getExtra().get("bookingTime_st");
            Object endTime = params.getExtra().get("bookingTime_nd");
            accountPrepaymentExportVO.setStartTime(Objects.isNull(startTime) ? "" : (String) startTime);
            accountPrepaymentExportVO.setEndTime(Objects.isNull(endTime) ? "" : (String) endTime);
            accountPrepaymentExportVO.setName(accountPrepayment.getName());
            accountPrepaymentExportVO.setCode(accountPrepayment.getCode());
            accountPrepaymentExportVO.setTotalPayAmount(excelVOList.stream().map(AccountDetailResultExcelVO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            accountPrepaymentExportVO.setDataList(excelVOList);
            this.superService.fillDayExcel(accountPrepaymentExportVO, response);
        } catch (Exception e) {
            response.setContentType("application/json");
            log.error("下载对账单失败:", e);
            throw new BizException(e.getMessage());
        }
    }
}


